import React, {Component} from 'react';
import CanvasSvg from "./canvasSVG";
import {getTree} from "./fib2";
import Menu from "./menu";
import Navbar from "./navbar";
import Details from "./details";
import {MinHeap} from "./Heap";
import $ from "jquery"
import {r, randomList, svgHeight, svgWidth, xBias, xTimes, yBias, yTimes} from "./Const";


let tree;
let before = false;
let pause = false;
class Recursion extends Component {
    constructor() {
        super();
        this.state = {
            root:undefined,
            reset: false,
            vertices:[],
            edges:[],
            current:-1,
            n:0,
            r:2,
            nrFlag:true,
            redNumber: -1,
            algo:0,
            offset:0,
            animation_stop: true,
            time: 500,
            leftMost: undefined,
            rightMost: undefined,
            upMost: undefined,
            downMost: undefined,
            width: undefined,
            height: undefined,
            // 随机选择的num
            selectNum: 0,
            // 最多可以选择到多少N
            MaxN: 11,

            select: false,

            setGreenFlag: false,
        }
        this.input = [];
        this.inputKey = 0;
    }


    handlePaused = (flag) => {
        // this.setState({isPaused: flag});
        before = pause;
        pause = flag;
    }

    handleGenerate = () => {
        let inputElement;
        let algo = this.state.algo;
        if (algo === 0) {
            let maxN = this.state.MaxN;
            let choice = 0 | Math.random() * maxN;
            this.setState({selectNum: choice});
            console.log(this.state.n);

        } else {
            inputElement = $("#input");
            let [list, key] = randomList(algo);
            inputElement.val(list.reduce((a, b) => {return a + "," + b;}));
            if (algo === 1) {
                let inputKey = $("#input-key");
                inputKey.val(key);
            }
        }
    }

    handleSpeed = (speed) => {
        let time = 900 - 8 * speed;
        this.setState({time})
    }

    changeSelect = () => {
        let select = !this.state.select;
        this.setState({select});
    }

    realOnReset = () => {
        this.changeSelect();
        this.onReset();
    }

    onReset = () => {
        before = pause = false;

        this.setState({reset: true, setGreenFlag: false, vertices: [], edges: []})
        this.state.vertices = [];
        $("#img").css({
                        scale: "1",
                        transform: "scale(1)",
                        left: "0",
                        top: "10px",
                      })

    }

    // 执行去除tab和空格的操作
    clearPure = (string) => {
        let final = "";
        for (let i = 0; i < string.length; i++) {
            if (string[i] !== " " || string[i] !== "\t")
                final += string[i];
        }
        return final;
    }

    clearTabSpace = (string) => {
        let final = this.clearPure(string);
        return final.split(",").map((value) => parseInt(value));
    }

    sort = (string) => {
        return string.sort((a,b) => a-b);
    }

    handleInput = () => {
        try {
            let inputElement = document.getElementById("input");
            let input = this.sort(this.clearTabSpace(inputElement.value));
            inputElement.value = input;
            this.input = input;
        } catch (e) {

        }

    }

    handleInputKey = () => {
        try {
            let inputKey = parseInt(this.clearPure(document.getElementById("input-key").value));
            this.inputKey = inputKey;
        } catch (e) {

        }

    }

    setAlgo = (pos, val) => {
        if (pos === 0) {
            this.setState({algo: val, nrFlag: val === 0});
        }
    }

    setN = (pos, val) => {
        if (pos === 0) {
            this.setState({n: val});
        }
    }

    setR = (pos, val) => {
        if (pos === 0) {
            this.setState({r: val});
        }
    }
    addNumber = async ()=>{
        if (before) {

        }
        else {
            this.setState({redNumber: -1});
        this.onReset();
        //
        if (this.state.reset) {
            this.onReset();
            await this.addNumberTemp();
        }
        await this.addNumberTemp();
        this.changeSelect();
        }


    }

    transForDraw = (tree, rootBias) => {
        tree.x = (tree.x - rootBias) * xTimes + xBias;
        tree.y = tree.y * yTimes + yBias;
        if (tree.left) {
            this.transForDraw(tree.left, rootBias);
        }
        if (tree.right) {
            this.transForDraw(tree.right, rootBias);
        }
    }

    transForLeftX = (tree, bias) => {
        tree.x += bias;
        if (tree.left) {
            this.transForLeftX(tree.left, bias);
        }
        if (tree.right) {
            this.transForLeftX(tree.right, bias);
        }
    }

    addNumberTemp = async () => {
            this.handleInput();
            this.handleInputKey();


            if (this.state.animation_stop) {
                this.setState({ animation_stop: true});
            tree = getTree(this.state.n,this.state.algo,this.state.r, [...this.input], this.inputKey);
            this.transForDraw(tree, tree.x);


            let leftMost = tree.getMostLeft(tree).x;
            if (leftMost - 2 * r < 0) {

                this.transForLeftX(tree, -leftMost + 2 * r);
            }

            leftMost = tree.getMostLeft(tree).x;

            let rightMost = tree.getMostRight(tree).x;
            let upMost = tree.y;
            let downMost = tree.getMostY(tree);
            let width = rightMost - leftMost + 4 * r;
            let height = downMost - upMost + 4 * r;

            width = width < 240 ? 240: width;
            height = height < 200 ? 200: height;

            this.setState({
                width,
                height
                });

            // console.log("leftMost");
            // console.log(leftMost);
            // console.log("rightMost");
            // console.log(rightMost);

            this.setState({edges:[],vertices:[], offset:tree.x, reset: false, animation_stop:false});
            this.state.vertices = [];
            // this.setState({});
                if (this.state.algo === 2) {
                     await this.recurHuffman(tree);
                } else if (this.state.algo === 1) {
                  await this.recurIfElse(tree);
                } else {
                    await this.recur(tree,undefined);

                }

            this.setState({animation_stop: true});

            }
    }

    // 这里出现bug的原因是 节点顺序设置错误
    recurHuffmanDraw = async (tree1, tree2, visited) => {

        if (!this.state.reset) {
            let parent = tree1.parent;
            let treeList = [tree1, tree2];
            let vertices = [...this.state.vertices];
            for (let i = 0; i < treeList.length; i++) {
                let current = treeList[i].getId();
                if (!visited[current]) {
                    vertices.push({label:treeList[i].tree.label.split(",")[0],val:0,
                        x:treeList[i].x,y:treeList[i].y,px:treeList[i].x,py:treeList[i].y,
                        isLeaf: treeList[i].isLeaf});
                    visited[treeList[i].getId()] = true;
                    if (this.state.reset) return false;this.setState({vertices});

                }
                    if (this.state.reset) return false;this.setState({vertices, current});
                    await sleep(this.state.time);
            }

            for (let i = 0; i < treeList.length; i++) {
                let edges = this.state.edges;
                edges.push({
                    x1: treeList[i].x,
                    y1: treeList[i].y,
                    x2: parent.x,
                    y2: parent.y
                });
                if (this.state.reset) return false;this.setState({edges});
            }

            if (!visited[parent.id]) {
                vertices.push({label:parent.tree.label.split(",")[0],val:0,
                        x:parent.x,y:parent.y,px:parent.x,py:parent.y});
                    visited[parent.getId()] = true;
                    if (this.state.reset) return false;this.setState({vertices});
            }
            let current = parent.id;
            if (this.state.reset) return false;this.setState({vertices, current});
            await sleep(this.state.time);
        }
        return true;
    }

    recurHuffman = async (node) => {
        try {

            let treeHeap = new MinHeap();
            let queue = [];
            queue.push(node);

            while (!this.state.reset && queue.length !== 0) {
                let [head] = queue.splice(0, 1);
                treeHeap.insert(head);
                if (head.left) {
                    queue.push(head.left);
                }
                if (head.right) {
                    queue.push(head.right);
                }

            }

            let heap = [...treeHeap.getAll()];
            let visited = {}
            for (let i = 0; !this.state.reset && i < heap.length; i++) {
                visited[heap[i].getId()] = false;
            }

            let flag = true;
            while (!this.state.reset && flag && treeHeap.getLength() !== 1) {
                let tree1 = treeHeap.pop();
                let tree2 = treeHeap.pop();

                await (flag = this.recurHuffmanDraw(tree1, tree2, visited));
            }
            if (flag ) {
                let vertices = [...this.state.vertices];
                let parent = treeHeap.peek();
                vertices.push({label:parent.tree.label.split(",")[0],val:0,
                        x:parent.x,y:parent.y,px:parent.x,py:parent.y});
             !this.state.reset && this.setState({vertices});
             await sleep(this.state.time * 2);
             !this.state.reset && this.setState({setGreenFlag: true});
            }
        } catch (e) {
        }

    }
    recurIfElseDraw = async (node, key) => {
        if (!this.state.reset) {
            let nowCondition = parseInt(node.tree.label.substring(1));

        // 处理本轮的情况
        // 先访问当前节点
        let vertices = this.state.vertices;
        let parent = node.parent;
        let current = vertices.length;
        if (!parent) {
            vertices.push({label: node.tree.label, val: node.tree.node, x:node.x,y:node.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices,current});
        }
        await sleep(this.state.time);
        let edges = this.state.edges;
        let nodeCurrent = current;

        for (let i = 0; i < 2; i++) {
            let child;
            let leftFlag = false;
            let stopFlag = true;
            if (i === 0 && node.left) {
                child = node.left;
                leftFlag = true;
                stopFlag = false;
            }

            if (i === 1 && node.right) {
                child = node.right;
                leftFlag = false;
                stopFlag = false;
            }

            if (stopFlag) continue;

            current = vertices.length;

            edges.push({
                x1:node.x,
                y1:node.y,
                x2:child.x,
                y2:child.y
            });

            !this.state.reset && this.setState({edges});

            vertices.push({label: child.tree.label, val: node.tree.node,
                x:child.x,y:child.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices, current});
            await sleep(this.state.time);
            if (leftFlag) {
                if (key < nowCondition) {
                    return;
                }
                let redNumber = current ;
                !this.state.reset && this.setState({vertices, redNumber});
                await sleep(this.state.time);
                // 回到父节点
                current = nodeCurrent;
                !this.state.reset && this.setState({vertices, current});
            } else {
                if (!child.left && !child.right) {
                    return;
                }
                await this.recurIfElseDraw(child, key);
            }

            }

        }
    }


    recurIfElse = async (node) => {
        try {
            let key = this.inputKey;
            await this.recurIfElseDraw(node, key);
        } catch {}
    }

    recur = async (node,parent)=>{
        try {
            let vertices = this.state.vertices;
        let current = this.state.vertices.length;

        if (!this.state.reset) {
             if( parent!==undefined ){

            if( node.left || node.right )
                vertices.push({label:node.tree.label,val:0,x:node.x,y:node.y,px:parent.x,py:parent.y});
            else
                vertices.push({label:node.tree.label,val:node.tree.node,x:node.x,y:node.y,px:parent.x,py:parent.y});
            !this.state.reset && this.setState({vertices,current});

            let edges = this.state.edges;
            edges.push({
                x1:parent.x,
                y1:parent.y,
                x2:node.x,
                y2:node.y
            });
            !this.state.reset && this.setState({edges});
        }else{
            if( node.left || node.right)
                vertices.push({label:node.tree.label,val:0,x:node.x,y:node.y,px:node.x,py:node.y});
            else
                vertices.push({label:node.tree.label,val:node.tree.node,x:node.x,y:node.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices,current});
        }
        await sleep(this.state.time);

        if (node.left) {
            !this.state.reset &&  await this.recur( node.left, node);
            !this.state.reset && this.setState({current});
            !this.state.reset && await sleep(this.state.time);
        }
        if (node.right) {
            !this.state.reset &&  await this.recur( node.right, node);
            !this.state.reset && this.setState({current});
            !this.state.reset && await sleep(this.state.time);
        }

        let verticess = [...this.state.vertices];
        verticess[current].val=node.tree.node;
        !this.state.reset && this.setState({vertices:verticess});

        }

        }
        catch (e) {
        }

    }
    render = () =>  {
        // $('body').css({"overflow-x": "hidden"});
        return (
            <div style={{
                overflow: "hidden",
                position:"relative"
                }}>
                <Navbar/>
                <Menu
                    handlePaused = {this.handlePaused}
                    select = {this.state.select}

                    MaxN = {this.state.MaxN}
                    selectNum = {this.state.selectNum}
                    onGenerate = {this.handleGenerate}
                    algo={this.state.algo}
                    handleSpeed = {this.handleSpeed}
                    setN={this.setN}
                    setR={this.setR}
                    setAlgo={this.setAlgo}
                    onStart={this.addNumber}
                    onReset={this.realOnReset}
                />
                {/*<Details*/}
                {/*    algo={this.state.algo}*/}
                {/*/>*/}
                <CanvasSvg
                    width = {this.state.width}
                    height = {this.state.height}
                    flagForDraw = {this.state.flagForDraw}
                    setGreenFlag = {this.state.setGreenFlag}

                    algorithm = {this.props.algo}
                    time = {this.state.time}
                    N = {this.state.n}
                    vertices={this.state.vertices}
                    edges={this.state.edges}
                    current={this.state.current}
                    offset={this.state.offset}
                    reset = {this.state.reset}
                    animation_stop = {this.state.animation_stop}
                    nrFlag = {this.state.nrFlag}
                    redNumber = {this.state.redNumber}
                />
            </div>
        );
    }
}

// const requestAnimationFrame = window.requestAnimationFrame
// || window.mozRequestAnimationFram
// || window.webkitRequestAnimationFrame
// || window.msRequestAnimationFrame
// || function(callback){ window.setTimeout(callback, 1000/ 60)}

const cancelAnimationFrame = window.cancelAnimationFrame
|| window.mozCancelAnimationFrame;

let allRef = null;

function animateTimeout(cb,time){

	let i = 0;

    let myRef = null;
    let rememberTime = time;
	myRef = requestAnimationFrame(function fn(){
        if (pause)
            time = 100000000000;
        else
            time = rememberTime;
		if(i > Math.floor(60 / (1000/time)) ){
			cb();
			cancelAnimationFrame(myRef);
            // return ;
		}
		i++;

		myRef = requestAnimationFrame(fn)
	})
}


function sleep(ms) {
    return new Promise(resolve => animateTimeout(resolve, ms));
}
export default Recursion;